#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SensitiveDataHunter Pro v1.0
企业级敏感信息明文传输检测框架
Kali Linux 原生集成版

作者: Security Research Team
版本: 1.0.0
更新: 2024-01-20

法律声明: 仅限授权安全测试使用
"""

import sys
import os
import time
import json
import asyncio
import re
import hashlib
import base64
import binascii
import math
import warnings
import argparse
from datetime import datetime
from typing import Dict, List, Optional, Any, Tuple
from abc import ABC, abstractmethod
from urllib.parse import urlparse, parse_qs
from pathlib import Path

warnings.filterwarnings('ignore')

# ==================== 核心依赖检查 ====================
DEPENDENCIES = {
    'PyQt5': False,
    'rich': False,
    'aiohttp': False,
    'aiolimiter': False,
    'yaml': False
}

try:
    from PyQt5.QtWidgets import (
        QApplication, QMainWindow, QWidget, QVBoxLayout, 
        QHBoxLayout, QLabel, QLineEdit, QPushButton, 
        QTextEdit, QProgressBar, QComboBox, QFileDialog, 
        QMessageBox, QTableWidget, QTableWidgetItem, 
        QHeaderView, QSplitter, QPlainTextEdit, QCheckBox,
        QGroupBox, QTabWidget, QTextBrowser, QStatusBar
    )
    from PyQt5.QtCore import pyqtSignal, QObject, Qt, QThread, QTimer
    from PyQt5.QtGui import QColor, QFont, QTextCursor
    DEPENDENCIES['PyQt5'] = True
except ImportError:
    print("[-] PyQt5 未安装，GUI 模式不可用")
    print("    安装命令: pip3 install PyQt5")

try:
    from rich.console import Console
    from rich.table import Table
    from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
    from rich.panel import Panel
    from rich.syntax import Syntax
    from rich.traceback import install as rich_traceback_install
    rich_traceback_install()
    DEPENDENCIES['rich'] = True
except ImportError:
    print("[-] Rich 库未安装，CLI 体验将降级")
    print("    安装命令: pip3 install rich")

try:
    import aiohttp
    DEPENDENCIES['aiohttp'] = True
except ImportError:
    print("[-] aiohttp 未安装，将使用同步模式")
    print("    安装命令: pip3 install aiohttp")

try:
    import aiolimiter
    DEPENDENCIES['aiolimiter'] = True
except ImportError:
    print("[-] aiolimiter 未安装，速率限制功能不可用")
    print("    安装命令: pip3 install aiolimiter")

try:
    import yaml
    DEPENDENCIES['yaml'] = True
except ImportError:
    print("[-] PyYAML 未安装，将使用JSON配置")
    print("    安装命令: pip3 install pyyaml")

# ==================== 1. 配置管理器 ====================
class ConfigManager:
    """支持 YAML/JSON 的层级配置管理器"""
    
    DEFAULT_CONFIG = {
        "scanner": {
            "timeout": 10,
            "rate_limit": 10,
            "max_threads": 20,
            "retry_count": 3,
            "user_agents": [
                "SensitiveDataHunter/1.0 (Kali Linux; Security Testing)",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
            ]
        },
        "detection": {
            "entropy_threshold": 4.5,
            "https_only": False,
            "check_response": True,
            "max_value_length": 100,
            "patterns": {
                "username": {
                    "enabled": True,
                    "fields": ["username", "user", "login", "account", "email", "phone", "mobile"],
                    "severity": "MEDIUM"
                },
                "password": {
                    "enabled": True,
                    "fields": ["password", "passwd", "pwd", "pass", "secret", "token"],
                    "severity": "CRITICAL"
                },
                "id_card": {
                    "enabled": True,
                    "patterns": [r'\b\d{17}[\dXx]\b', r'\b\d{15}\b'],
                    "severity": "HIGH"
                },
                "phone": {
                    "enabled": True,
                    "patterns": [r'\b1[3-9]\d{9}\b', r'\+86\s*1[3-9]\d{9}\b'],
                    "severity": "HIGH"
                },
                "bank_card": {
                    "enabled": True,
                    "patterns": [r'\b\d{16,19}\b'],
                    "severity": "CRITICAL"
                },
                "api_key": {
                    "enabled": True,
                    "patterns": [
                        r'(?i)api[_-]?key\s*[=:]\s*[a-zA-Z0-9]{16,}',
                        r'(?i)access[_-]?token\s*[=:]\s*[a-zA-Z0-9]{16,}'
                    ],
                    "severity": "HIGH"
                },
                "credit_card": {
                    "enabled": True,
                    "patterns": [r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b'],
                    "severity": "CRITICAL"
                }
            }
        },
        "security": {
            "require_auth": False,
            "allowed_targets": [],
            "max_scan_duration": 3600
        },
        "output": {
            "save_requests": True,
            "save_responses": False,
            "max_response_size": 1048576,
            "report_format": "html",
            "output_dir": "~/sensitivedata_reports"
        }
    }

    def __init__(self, config_path: str = "~/.sensitivedatahunter/config.yaml"):
        self.config_path = Path(config_path).expanduser()
        self.config = self._load_config()

    def _load_config(self) -> Dict[str, Any]:
        """从 YAML/JSON 加载配置"""
        if not self.config_path.exists():
            self.config_path.parent.mkdir(parents=True, exist_ok=True)
            self._save_config(self.DEFAULT_CONFIG)
            return self.DEFAULT_CONFIG.copy()

        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                if self.config_path.suffix in ['.yaml', '.yml'] and DEPENDENCIES['yaml']:
                    import yaml
                    loaded = yaml.safe_load(f) or {}
                else:
                    loaded = json.load(f)
            
            # 合并默认配置
            return self._merge_configs(self.DEFAULT_CONFIG, loaded)
        
        except Exception as e:
            print(f"[!] 配置加载失败: {e}，使用默认配置")
            return self.DEFAULT_CONFIG.copy()

    def _merge_configs(self, default: Dict, loaded: Dict) -> Dict:
        """深度合并配置"""
        result = default.copy()
        for key, value in loaded.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._merge_configs(result[key], value)
            else:
                result[key] = value
        return result

    def _save_config(self, config: Dict[str, Any]):
        """保存配置到文件"""
        try:
            self.config_path.parent.mkdir(parents=True, exist_ok=True)
            with open(self.config_path, 'w', encoding='utf-8') as f:
                if self.config_path.suffix in ['.yaml', '.yml'] and DEPENDENCIES['yaml']:
                    import yaml
                    yaml.dump(config, f, default_flow_style=False, indent=2, allow_unicode=True)
                else:
                    json.dump(config, f, indent=2, ensure_ascii=False)
        except Exception as e:
            print(f"[!] 配置保存失败: {e}")

    def get(self, key: str, default: Any = None) -> Any:
        """点分式获取配置值"""
        keys = key.split('.')
        value = self.config
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            return default

    def set(self, key: str, value: Any, save: bool = True):
        """设置配置值"""
        keys = key.split('.')
        config = self.config
        for k in keys[:-1]:
            config = config.setdefault(k, {})
        config[keys[-1]] = value
        
        if save:
            self._save_config(self.config)

# ==================== 2. 敏感信息检测器 ====================
class SensitiveDataDetector:
    """检测各类敏感信息"""
    
    # 正则表达式模式
    PATTERNS = {
        "username": {
            "regex": [
                r'(?i)(?:username|user|login|account)\s*[=:]\s*([^\s&\'"]+)',
                r'(?i)(?:email|mail)\s*[=:]\s*([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})'
            ],
            "description": "用户名/账号"
        },
        "password": {
            "regex": [
                r'(?i)(?:password|passwd|pwd|pass|secret)\s*[=:]\s*([^\s&\'"]+)',
            ],
            "description": "密码/密钥"
        },
        "id_card": {
            "regex": [
                r'\b\d{17}[\dXx]\b',
                r'\b\d{15}\b'
            ],
            "description": "身份证号码"
        },
        "phone": {
            "regex": [
                r'\b1[3-9]\d{9}\b',
                r'\+86\s*1[3-9]\d{9}\b',
                r'0086\s*1[3-9]\d{9}\b'
            ],
            "description": "手机号码"
        },
        "bank_card": {
            "regex": [
                r'\b\d{16,19}\b'
            ],
            "description": "银行卡号"
        },
        "credit_card": {
            "regex": [
                r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b'
            ],
            "description": "信用卡号"
        },
        "api_key": {
            "regex": [
                r'(?i)api[_-]?key\s*[=:]\s*([a-zA-Z0-9_-]{16,})',
                r'(?i)access[_-]?token\s*[=:]\s*([a-zA-Z0-9_-]{16,})',
                r'(?i)bearer\s+([a-zA-Z0-9_-]{16,})'
            ],
            "description": "API密钥"
        }
    }

    # 误报过滤规则
    FALSE_POSITIVE_PATTERNS = {
        "common": [
            r'^(null|undefined|none|test|demo|example|sample)$',
            r'^\d+$',  # 纯数字
            r'^[a-zA-Z]+$',  # 纯字母
            r'<[^>]+>',  # HTML标签
            r'^\{\{.*\}\}$',  # 模板变量
        ],
        "password": [
            r'^(password|123456|admin|root|test)$',
            r'^[*]{6,}$',  # 星号掩码
        ],
        "email": [
            r'@(example|test|demo)\.(com|org|net)$'
        ]
    }

    def __init__(self, config: ConfigManager):
        self.config = config
        self.compiled_patterns = self._compile_patterns()
        self.false_positive_patterns = self._compile_false_positive_patterns()

    def _compile_patterns(self) -> Dict[str, List[re.Pattern]]:
        """编译正则表达式"""
        compiled = {}
        patterns_config = self.config.get("detection.patterns", {})
        
        for data_type, pattern_info in self.PATTERNS.items():
            config = patterns_config.get(data_type, {})
            if not config.get("enabled", True):
                continue
            
            compiled[data_type] = []
            
            # 使用配置中的自定义模式或默认模式
            patterns = config.get("patterns", pattern_info["regex"])
            if isinstance(patterns, str):
                patterns = [patterns]
            
            for pattern in patterns:
                try:
                    compiled[data_type].append(re.compile(pattern, re.IGNORECASE))
                except re.error as e:
                    print(f"[!] 正则表达式编译失败 ({data_type}): {e}")
        
        return compiled

    def _compile_false_positive_patterns(self) -> Dict[str, List[re.Pattern]]:
        """编译误报过滤模式"""
        compiled = {}
        for category, patterns in self.FALSE_POSITIVE_PATTERNS.items():
            compiled[category] = [re.compile(p, re.IGNORECASE) for p in patterns]
        return compiled

    def detect(self, text: str, source: str = "unknown") -> List[Dict[str, Any]]:
        """检测文本中的敏感信息"""
        if not text or not isinstance(text, str):
            return []
        
        findings = []
        max_length = self.config.get("detection.max_value_length", 100)
        
        for data_type, patterns in self.compiled_patterns.items():
            severity = self.config.get(f"detection.patterns.{data_type}.severity", "HIGH")
            
            for pattern in patterns:
                try:
                    matches = pattern.finditer(text)
                    for match in matches:
                        value = match.group(1) if match.groups() else match.group(0)
                        
                        # 限制值长度
                        if len(value) > max_length:
                            value = value[:max_length]
                        
                        # 过滤误报
                        if self._is_false_positive(value, data_type):
                            continue
                        
                        # 检查是否加密
                        entropy = self._calculate_entropy(value)
                        is_encrypted = self.is_encrypted(value)
                        
                        findings.append({
                            "type": data_type,
                            "value": value,
                            "severity": severity,
                            "position": match.span(),
                            "source": source,
                            "entropy": entropy,
                            "encrypted": is_encrypted,
                            "description": self.PATTERNS[data_type]["description"]
                        })
                except Exception as e:
                    print(f"[!] 检测异常 ({data_type}): {e}")
                    continue
        
        return findings

    def _is_false_positive(self, value: str, data_type: str) -> bool:
        """检测是否为误报"""
        if not value or len(value) < 3:
            return True
        
        value_lower = value.lower().strip()
        
        # 通用误报检查
        for pattern in self.false_positive_patterns.get("common", []):
            if pattern.match(value_lower):
                return True
        
        # 特定类型误报检查
        if data_type in self.false_positive_patterns:
            for pattern in self.false_positive_patterns[data_type]:
                if pattern.match(value_lower):
                    return True
        
        # 特殊检查
        if data_type == "bank_card":
            # Luhn算法验证银行卡号
            if not self._luhn_check(value.replace(' ', '').replace('-', '')):
                return True
        
        if data_type == "id_card":
            # 简单验证身份证号格式
            if not self._validate_id_card(value):
                return True
        
        return False

    def _luhn_check(self, card_number: str) -> bool:
        """Luhn算法验证信用卡/银行卡号"""
        try:
            digits = [int(d) for d in card_number if d.isdigit()]
            if len(digits) < 13:
                return False
            
            checksum = 0
            for i, digit in enumerate(reversed(digits)):
                if i % 2 == 1:
                    digit *= 2
                    if digit > 9:
                        digit -= 9
                checksum += digit
            
            return checksum % 10 == 0
        except:
            return False

    def _validate_id_card(self, id_card: str) -> bool:
        """验证身份证号格式"""
        if len(id_card) not in [15, 18]:
            return False
        
        # 简单的地区码检查
        area_code = id_card[:2]
        if not area_code.isdigit() or int(area_code) < 11 or int(area_code) > 91:
            return False
        
        return True

    def _calculate_entropy(self, text: str) -> float:
        """计算字符串的熵值"""
        if not text:
            return 0.0
        
        freq = {}
        for char in text:
            freq[char] = freq.get(char, 0) + 1
        
        entropy = 0.0
        length = len(text)
        for count in freq.values():
            p = count / length
            entropy -= p * math.log2(p)
        
        return round(entropy, 3)

    def is_encrypted(self, text: str) -> bool:
        """判断内容是否加密"""
        if not text or len(text) < 8:
            return False
        
        entropy = self._calculate_entropy(text)
        threshold = self.config.get("detection.entropy_threshold", 4.5)
        
        # Base64编码检测
        try:
            if re.match(r'^[A-Za-z0-9+/]+=*$', text):
                base64.b64decode(text)
                return True
        except:
            pass
        
        # 十六进制编码检测
        if re.match(r'^[0-9a-fA-F]+$', text) and len(text) % 2 == 0:
            return True
        
        return entropy > threshold

# ==================== 3. 漏洞对象 ====================
class Vulnerability:
    """漏洞对象"""
    
    RISK_LEVELS = {
        "CRITICAL": {
            "score": 10.0,
            "color": "#dc3545",
            "description": "严重风险，需立即修复",
            "owasp_category": "A02:2021 - 加密失败"
        },
        "HIGH": {
            "score": 8.0,
            "color": "#fd7e14",
            "description": "高风险，需尽快修复",
            "owasp_category": "A02:2021 - 加密失败"
        },
        "MEDIUM": {
            "score": 5.0,
            "color": "#ffc107",
            "description": "中等风险，建议修复",
            "owasp_category": "A02:2021 - 加密失败"
        },
        "LOW": {
            "score": 3.0,
            "color": "#28a745",
            "description": "低风险，可择期修复",
            "owasp_category": "A05:2021 - 安全配置错误"
        },
        "INFO": {
            "score": 0.0,
            "color": "#6c757d",
            "description": "信息性发现",
            "owasp_category": "N/A"
        }
    }
    
    IMPACT_DESCRIPTIONS = {
        "password_plaintext": {
            "impact": "密码以明文形式传输，攻击者可通过中间人攻击轻松窃取用户凭证",
            "consequences": [
                "账户完全接管",
                "横向渗透其他系统",
                "用户凭证泄露导致大规模安全事件",
                "违反PCI DSS、GDPR等合规要求"
            ],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
            "real_world_cases": [
                "2017年Equifax数据泄露：明文传输导致1.47亿用户数据泄露",
                "2019年Capital One：明文凭证泄露影响1亿用户"
            ]
        },
        "id_card_plaintext": {
            "impact": "身份证号明文传输，可能导致身份盗用和金融欺诈",
            "consequences": [
                "身份盗用和冒充",
                "金融欺诈和贷款诈骗",
                "个人隐私完全泄露",
                "违反《个人信息保护法》"
            ],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N",
            "real_world_cases": [
                "2020年某省社保系统：身份证号泄露影响500万用户"
            ]
        },
        "phone_plaintext": {
            "impact": "手机号明文传输，可能被用于垃圾短信和电话诈骗",
            "consequences": [
                "骚扰电话和垃圾短信",
                "SIM卡交换攻击",
                "二次钓鱼攻击",
                "隐私侵犯"
            ],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
            "real_world_cases": [
                "2022年某外卖平台：手机号泄露导致用户被精准诈骗"
            ]
        },
        "bank_card_plaintext": {
            "impact": "银行卡号明文传输，可能导致金融资金被盗",
            "consequences": [
                "银行卡盗刷",
                "金融欺诈",
                "资金损失",
                "违反PCI DSS标准"
            ],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "real_world_cases": [
                "2013年Target数据泄露：4000万信用卡信息被盗"
            ]
        },
        "api_key_plaintext": {
            "impact": "API密钥明文传输，可能导致未授权访问和数据泄露",
            "consequences": [
                "API滥用和恶意调用",
                "数据泄露",
                "服务资源耗尽",
                "横向渗透"
            ],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L",
            "real_world_cases": [
                "2020年Twitter API泄露：攻击者获取了内部系统访问权限"
            ]
        }
    }
    
    REMEDIATION_ADVICE = {
        "password_plaintext": {
            "immediate": [
                "立即启用HTTPS，强制所有登录请求使用TLS 1.2+加密",
                "实施HTTP严格传输安全(HSTS)策略",
                "在Web服务器配置中禁用HTTP协议"
            ],
            "short_term": [
                "实现客户端密码哈希：使用bcrypt或Argon2",
                "添加证书锁定(Certificate Pinning)防止中间人攻击",
                "实施传输层加密验证机制"
            ],
            "long_term": [
                "采用OAuth 2.0/OpenID Connect标准认证协议",
                "实施零信任网络架构",
                "定期进行渗透测试和安全审计"
            ],
            "code_example": """# Python Flask 示例：强制HTTPS
from flask import Flask, request, redirect
from werkzeug.security import generate_password_hash

app = Flask(__name__)

@app.before_request
def force_https():
    if request.scheme == 'http':
        return redirect(request.url.replace('http://', 'https://'), 301)

@app.route('/api/login', methods=['POST'])
def secure_login():
    data = request.get_json()
    hashed_pw = generate_password_hash(data['password'])
    # 验证逻辑...
    return {'token': 'secure_token'}
"""
        },
        "id_card_plaintext": {
            "immediate": [
                "立即启用HTTPS加密传输",
                "在应用层对身份证号进行AES-256加密",
                "实施字段级加密策略"
            ],
            "short_term": [
                "采用令牌化(Tokenization)技术",
                "实施数据脱敏：只传输部分身份证号",
                "添加访问控制和审计日志"
            ],
            "long_term": [
                "建立数据分类分级制度",
                "实施数据丢失防护(DLP)系统",
                "符合《个人信息保护法》要求"
            ],
            "code_example": """# Python 示例：身份证号加密
from cryptography.fernet import Fernet

class IdCardProtector:
    def __init__(self, key):
        self.cipher = Fernet(key)
    
    def encrypt(self, id_card):
        return self.cipher.encrypt(id_card.encode()).decode()
    
    def mask(self, id_card):
        return id_card[:3] + "*********" + id_card[-4:]
"""
        },
        "api_key_plaintext": {
            "immediate": [
                "立即启用HTTPS和TLS 1.2+",
                "实施API密钥轮换机制",
                "使用HTTP签名验证请求完整性"
            ],
            "short_term": [
                "采用JWT令牌代替API密钥",
                "实施API网关和速率限制",
                "添加IP白名单和设备指纹"
            ],
            "long_term": [
                "采用OAuth 2.0客户端凭证流",
                "实施API安全网关",
                "建立API安全监控和异常检测"
            ],
            "code_example": """# Python 示例：JWT替代API密钥
import jwt
from datetime import datetime, timedelta

def generate_jwt_token(client_id):
    payload = {
        'client_id': client_id,
        'exp': datetime.utcnow() + timedelta(hours=1)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
"""
        }
    }

    def __init__(self, vuln_type: str, param: str, value: str, 
                 severity: str, evidence: str, confidence: float = 0.9,
                 test_details: Optional[Dict[str, Any]] = None):
        self.type = vuln_type
        self.param = param
        self.value = value
        self.severity = severity
        self.evidence = evidence
        self.confidence = min(max(confidence, 0.0), 1.0)
        self.timestamp = datetime.now()
        self.test_details = test_details or {}
        
        self.risk_score = self._calculate_risk_score()
        self.impact = self._get_impact_description()
        self.remediation = self._get_remediation_advice()

    def _calculate_risk_score(self) -> float:
        """计算综合风险评分"""
        base_score = self.RISK_LEVELS.get(self.severity, {}).get("score", 0.0)
        adjusted_score = base_score * self.confidence
        
        if self.type == "password_plaintext":
            adjusted_score *= 1.2
        
        return round(min(adjusted_score, 10.0), 2)

    def _get_impact_description(self) -> Dict[str, Any]:
        """获取漏洞危害描述"""
        return self.IMPACT_DESCRIPTIONS.get(self.type, {
            "impact": "敏感信息明文传输可能导致数据泄露",
            "consequences": ["数据被窃听", "隐私泄露", "合规风险"],
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
            "real_world_cases": []
        })

    def _get_remediation_advice(self) -> Dict[str, Any]:
        """获取修复建议"""
        base_type = self.type.split('_')[0] + "_plaintext"
        return self.REMEDIATION_ADVICE.get(base_type, {
            "immediate": ["启用HTTPS", "加密敏感数据"],
            "short_term": ["实施安全传输标准"],
            "long_term": ["建立安全开发流程"],
            "code_example": "# 请参考OWASP安全编码指南"
        })

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "type": self.type,
            "param": self.param,
            "value": self.value,
            "severity": self.severity,
            "evidence": self.evidence,
            "confidence": self.confidence,
            "risk_score": self.risk_score,
            "timestamp": self.timestamp.isoformat(),
            "impact": self.impact,
            "remediation": self.remediation,
            "test_details": self.test_details
        }

    def __hash__(self):
        return hash((self.type, self.param, self.value))

    def __eq__(self, other):
        if not isinstance(other, Vulnerability):
            return False
        return (self.type, self.param, self.value) == (other.type, other.param, other.value)

# ==================== 4. 测试过程记录器 ====================
class TestProcess:
    """详细记录测试过程"""
    
    def __init__(self):
        self.steps = []
        self.start_time = None
        self.end_time = None
        self.requests_sent = 0
        self.responses_received = 0
        self.errors_encountered = 0
        self.sensitive_data_found = 0
    
    def start(self):
        """开始测试"""
        self.start_time = datetime.now()
        self.add_step("测试开始", "初始化扫描引擎", "INFO")
    
    def add_step(self, title: str, description: str, level: str = "INFO", 
                 details: Optional[Dict[str, Any]] = None):
        """添加测试步骤"""
        step = {
            "timestamp": datetime.now().isoformat(),
            "title": title,
            "description": description,
            "level": level,
            "details": details or {}
        }
        self.steps.append(step)
    
    def end(self):
        """结束测试"""
        self.end_time = datetime.now()
        if self.start_time:
            duration = (self.end_time - self.start_time).total_seconds()
            self.add_step(
                "测试完成", 
                f"总耗时: {duration:.2f}秒, 发现敏感数据: {self.sensitive_data_found}条",
                "SUCCESS"
            )

# ==================== 5. 检测策略引擎 ====================
class DetectionStrategy(ABC):
    """检测策略基类"""
    
    @abstractmethod
    def analyze(self, request_data: Dict[str, Any], response_data: Optional[Dict[str, Any]], 
                context: Dict[str, Any]) -> List[Vulnerability]:
        """分析请求和响应"""
        pass

class PlaintextTransmissionStrategy(DetectionStrategy):
    """明文传输检测策略"""
    
    def __init__(self, config: ConfigManager, detector: SensitiveDataDetector):
        self.config = config
        self.detector = detector
    
    def analyze(self, request_data: Dict[str, Any], response_data: Optional[Dict[str, Any]], 
                context: Dict[str, Any]) -> List[Vulnerability]:
        """分析请求和响应中的敏感信息"""
        vulnerabilities = []
        test_process = context.get('test_process')
        url = request_data.get('url', '')
        
        parsed_url = urlparse(url)
        is_https = parsed_url.scheme == 'https'
        
        # 检查协议
        if not is_https:
            if test_process:
                test_process.add_step(
                    "协议检查",
                    f"检测到非HTTPS协议: {url}",
                    "WARNING"
                )
            
            vulnerabilities.append(Vulnerability(
                vuln_type="insecure_protocol",
                param="url",
                value=url,
                severity="HIGH",
                evidence=f"URL使用非加密协议: {parsed_url.scheme}",
                confidence=1.0,
                test_details={"protocol": parsed_url.scheme, "url": url}
            ))
        
        # 检测URL参数
        query_params = parse_qs(parsed_url.query)
        for param, values in query_params.items():
            for value in values:
                findings = self.detector.detect(str(value), f"query.{param}")
                for finding in findings:
                    vuln = self._create_vulnerability(finding, "request", param, url, is_https)
                    vulnerabilities.append(vuln)
                    if test_process:
                        test_process.sensitive_data_found += 1
                        test_process.add_step(
                            "敏感数据检测",
                            f"发现{finding['description']}: {param}",
                            "ERROR",
                            {"位置": "URL参数", "类型": finding['type']}
                        )
        
        # 检测请求体
        data = request_data.get('data', {})
        if isinstance(data, dict):
            for param, value in data.items():
                if isinstance(value, str):
                    findings = self.detector.detect(value, f"body.{param}")
                    for finding in findings:
                        vuln = self._create_vulnerability(finding, "request", param, url, is_https)
                        vulnerabilities.append(vuln)
                        if test_process:
                            test_process.sensitive_data_found += 1
        
        # 检测响应
        if response_data and self.config.get("detection.check_response", True):
            response_text = response_data.get('text', '')
            if response_text:
                findings = self.detector.detect(response_text, "response.body")
                for finding in findings:
                    vuln = self._create_vulnerability(finding, "response", "body", url, is_https)
                    vulnerabilities.append(vuln)
                    if test_process:
                        test_process.sensitive_data_found += 1
        
        return vulnerabilities
    
    def _create_vulnerability(self, finding: Dict[str, Any], location: str, 
                             param: str, url: str, is_https: bool) -> Vulnerability:
        """创建漏洞对象"""
        severity = finding['severity']
        
        if finding['type'] == 'password' and not is_https:
            severity = "CRITICAL"
        elif not is_https:
            severity_levels = ["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"]
            current_idx = severity_levels.index(severity)
            severity = severity_levels[min(current_idx + 1, len(severity_levels) - 1)]
        
        vuln_type = f"{finding['type']}_plaintext"
        evidence = f"在{location}中发现{finding['description']}明文传输"
        if not is_https:
            evidence += f" (非加密协议: {urlparse(url).scheme})"
        
        return Vulnerability(
            vuln_type=vuln_type,
            param=param,
            value=finding['value'],
            severity=severity,
            evidence=evidence,
            confidence=0.9,
            test_details={
                "location": location,
                "protocol": urlparse(url).scheme,
                "is_https": is_https,
                "entropy": finding.get('entropy', 0),
                "encrypted": finding.get('encrypted', False)
            }
        )

# ==================== 6. 异步扫描引擎 ====================
class AsyncSensitiveDataScanner:
    """异步敏感信息扫描引擎"""
    
    def __init__(self, config: ConfigManager):
        self.config = config
        self.detector = SensitiveDataDetector(config)
        self.strategies = [PlaintextTransmissionStrategy(config, self.detector)]
        self.test_process = TestProcess()
        self.vulnerabilities = []
        
        if DEPENDENCIES['aiolimiter']:
            self.limiter = aiolimiter.AsyncLimiter(
                config.get("scanner.rate_limit", 10), 1
            )
        else:
            self.limiter = None

    async def _send_request(self, session: aiohttp.ClientSession, 
                           target: Dict[str, Any], request_id: str) -> Dict[str, Any]:
        """发送HTTP请求"""
        try:
            self.test_process.requests_sent += 1
            
            url = target['url']
            method = target['method']
            headers = target.get('headers', {})
            data = target.get('data', {})
            
            timeout = aiohttp.ClientTimeout(total=self.config.get("scanner.timeout", 10))
            
            start_time = time.time()
            
            if self.limiter:
                async with self.limiter:
                    response = await self._do_request(session, method, url, headers, data, timeout)
            else:
                response = await self._do_request(session, method, url, headers, data, timeout)
            
            duration = round(time.time() - start_time, 3)
            
            self.test_process.responses_received += 1
            self.test_process.add_step(
                f"HTTP请求 {request_id}",
                f"{method} {url} -> {response['status_code']} ({duration}s)",
                "INFO",
                {
                    "方法": method,
                    "URL": url,
                    "状态码": response['status_code'],
                    "耗时": f"{duration}s"
                }
            )
            
            return response
            
        except asyncio.TimeoutError:
            self.test_process.errors_encountered += 1
            self.test_process.add_step(
                f"请求超时 {request_id}",
                f"请求超时: {target.get('url')}",
                "ERROR"
            )
            return {"error": "timeout"}
        except Exception as e:
            self.test_process.errors_encountered += 1
            self.test_process.add_step(
                f"请求失败 {request_id}",
                f"错误: {str(e)}",
                "ERROR"
            )
            return {"error": str(e)}

    async def _do_request(self, session, method, url, headers, data, timeout):
        """执行实际的HTTP请求"""
        if method == "GET":
            async with session.get(url, headers=headers, params=data, timeout=timeout) as resp:
                text = await resp.text()
                return {
                    "id": "REQ-001",
                    "status_code": resp.status,
                    "text": text,
                    "headers": dict(resp.headers),
                    "duration": 0
                }
        else:
            json_data = json.dumps(data) if isinstance(data, dict) else data
            async with session.post(url, headers=headers, data=json_data, timeout=timeout) as resp:
                text = await resp.text()
                return {
                    "id": "REQ-001",
                    "status_code": resp.status,
                    "text": text,
                    "headers": dict(resp.headers),
                    "duration": 0
                }

    async def scan(self, target: Dict[str, Any], 
                  callback: Optional[callable] = None) -> List[Vulnerability]:
        """执行扫描"""
        self.test_process.start()
        
        if callback:
            callback("初始化扫描...")
        
        try:
            if not DEPENDENCIES['aiohttp']:
                if callback:
                    callback("错误: aiohttp未安装")
                return []
            
            connector = aiohttp.TCPConnector(
                limit=self.config.get("scanner.max_threads", 20),
                ssl=False
            )
            
            async with aiohttp.ClientSession(connector=connector) as session:
                if callback:
                    callback(f"发送请求到 {target['url']}")
                
                request_data = await self._send_request(session, target, "REQ-001")
                
                if "error" in request_data:
                    self.test_process.end()
                    return []
                
                response_data = None
                if self.config.get("detection.check_response", True):
                    response_data = {
                        "status_code": request_data['status_code'],
                        "text": request_data['text'],
                        "headers": request_data['headers']
                    }
                
                if callback:
                    callback("执行检测策略...")
                
                self.test_process.add_step("策略分析", "开始执行检测策略", "INFO")
                
                all_vulnerabilities = []
                for strategy in self.strategies:
                    strategy_name = strategy.__class__.__name__
                    if callback:
                        callback(f"运行 {strategy_name}...")
                    
                    vulns = strategy.analyze(target, response_data, {
                        'test_process': self.test_process
                    })
                    
                    for vuln in vulns:
                        if vuln not in all_vulnerabilities:
                            all_vulnerabilities.append(vuln)
                            if callback:
                                callback(f"发现漏洞: {vuln.type} (风险评分: {vuln.risk_score})")
                
                self.vulnerabilities = all_vulnerabilities
                self.test_process.end()
                
                if callback:
                    callback(f"扫描完成，发现 {len(self.vulnerabilities)} 个漏洞")
                
                return self.vulnerabilities
                
        except Exception as e:
            self.test_process.add_step("扫描异常", str(e), "ERROR")
            self.test_process.end()
            if callback:
                callback(f"扫描异常: {str(e)}")
            return []

# ==================== 7. GUI界面 ====================
if DEPENDENCIES['PyQt5']:
    
    class DarkTheme:
        """Kali Linux风格Dark Mode主题"""
        STYLESHEET = """
        QMainWindow {
            background-color: #1e1e1e;
            color: #d4d4d4;
        }
        QWidget {
            background-color: #1e1e1e;
            color: #d4d4d4;
        }
        QTabWidget::pane {
            border: 1px solid #3e3e42;
            background: #252526;
        }
        QTabBar::tab {
            background: #2d2d30;
            color: #cccccc;
            padding: 8px 20px;
            margin-right: 2px;
        }
        QTabBar::tab:selected {
            background: #007acc;
            color: white;
        }
        QPushButton {
            background-color: #007acc;
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            font-weight: bold;
        }
        QPushButton:hover {
            background-color: #005a9e;
        }
        QPushButton:disabled {
            background-color: #3e3e42;
            color: #6e6e70;
        }
        QLineEdit, QPlainTextEdit, QTextEdit {
            background-color: #2d2d30;
            color: #d4d4d4;
            border: 1px solid #3e3e42;
            padding: 6px;
            border-radius: 3px;
        }
        QTableWidget {
            background-color: #1e1e1e;
            color: #d4d4d4;
            gridline-color: #3e3e42;
            border: 1px solid #3e3e42;
        }
        QHeaderView::section {
            background-color: #2d2d30;
            color: #d4d4d4;
            padding: 6px;
            border: none;
            font-weight: bold;
        }
        QProgressBar {
            background-color: #3e3e42;
            border: none;
            height: 12px;
            border-radius: 6px;
        }
        QProgressBar::chunk {
            background-color: #007acc;
            border-radius: 6px;
        }
        QCheckBox {
            color: #d4d4d4;
            spacing: 8px;
        }
        QGroupBox {
            border: 1px solid #3e3e42;
            border-radius: 4px;
            margin-top: 8px;
            padding-top: 8px;
        }
        QGroupBox::title {
            subcontrol-origin: margin;
            left: 10px;
            padding: 0 5px;
            color: #007acc;
            font-weight: bold;
        }
        QTextBrowser {
            background-color: #2d2d30;
            color: #d4d4d4;
            border: 1px solid #3e3e42;
        }
        """

    class MainWindow(QMainWindow):
        """主窗口"""
        scan_started = pyqtSignal()
        scan_finished = pyqtSignal(list)

        def __init__(self, config: ConfigManager):
            super().__init__()
            self.config = config
            self.scanner = None
            self.scan_thread = None
            self.scan_worker = None
            self.scan_is_running = False
            
            self.setWindowTitle("SensitiveDataHunter Pro v1.0 - Kali Linux Edition")
            self.setGeometry(100, 100, 1400, 900)
            self.setStyleSheet(DarkTheme.STYLESHEET)
            
            self._init_ui()
            self._connect_signals()

        def _init_ui(self):
            """初始化UI"""
            central_widget = QWidget()
            self.setCentralWidget(central_widget)
            main_layout = QVBoxLayout(central_widget)
            
            self.tab_widget = QTabWidget()
            
            # 扫描标签页
            scan_tab = QWidget()
            scan_layout = QHBoxLayout(scan_tab)
            
            left_panel = self._create_request_panel()
            right_panel = self._create_result_panel()
            
            splitter = QSplitter(Qt.Horizontal)
            splitter.addWidget(left_panel)
            splitter.addWidget(right_panel)
            splitter.setSizes([400, 1000])
            
            scan_layout.addWidget(splitter)
            self.tab_widget.addTab(scan_tab, "🔍 扫描")
            
            # 测试过程标签页
            self.test_process_tab = QTextBrowser()
            self.tab_widget.addTab(self.test_process_tab, "📋 测试过程")
            
            # 漏洞详情标签页
            self.vuln_details_tab = QTextBrowser()
            self.tab_widget.addTab(self.vuln_details_tab, "🔬 漏洞详情")
            
            main_layout.addWidget(self.tab_widget)
            
            # 状态栏
            self.statusBar().showMessage("就绪")

        def _create_request_panel(self) -> QGroupBox:
            """创建请求配置面板"""
            group = QGroupBox("请求配置")
            layout = QVBoxLayout()
            
            layout.addWidget(QLabel("目标 URL:"))
            self.url_input = QLineEdit()
            self.url_input.setPlaceholderText("https://example.com/api/login")
            layout.addWidget(self.url_input)
            
            layout.addWidget(QLabel("HTTP 方法:"))
            self.method_combo = QComboBox()
            self.method_combo.addItems(["POST", "GET", "PUT", "PATCH", "DELETE"])
            layout.addWidget(self.method_combo)
            
            layout.addWidget(QLabel("请求头 (JSON):"))
            self.headers_edit = QPlainTextEdit()
            self.headers_edit.setPlainText(json.dumps({
                "Content-Type": "application/json",
                "User-Agent": "SensitiveDataHunter/1.0"
            }, indent=2))
            self.headers_edit.setMaximumHeight(150)
            layout.addWidget(self.headers_edit)
            
            layout.addWidget(QLabel("请求体/参数 (JSON):"))
            self.body_edit = QPlainTextEdit()
            self.body_edit.setPlainText(json.dumps({
                "username": "test@example.com",
                "password": "P@ssw0rd123"
            }, indent=2))
            self.body_edit.setMaximumHeight(150)
            layout.addWidget(self.body_edit)
            
            # 检测选项
            layout.addWidget(QLabel("检测选项:"))
            options_group = QGroupBox()
            options_layout = QVBoxLayout()
            
            self.https_only_check = QCheckBox("仅检测HTTPS")
            self.https_only_check.setChecked(self.config.get("detection.https_only", False))
            options_layout.addWidget(self.https_only_check)
            
            self.check_response_check = QCheckBox("检查响应数据")
            self.check_response_check.setChecked(self.config.get("detection.check_response", True))
            options_layout.addWidget(self.check_response_check)
            
            options_group.setLayout(options_layout)
            layout.addWidget(options_group)
            
            # 导入功能
            import_btn = QPushButton("📥 导入HAR/JSON请求")
            import_btn.clicked.connect(self.import_request)
            layout.addWidget(import_btn)
            
            layout.addStretch()
            group.setLayout(layout)
            return group

        def _create_result_panel(self) -> QGroupBox:
            """创建结果面板"""
            group = QGroupBox("扫描结果")
            layout = QVBoxLayout()
            
            # 控制按钮
            btn_layout = QHBoxLayout()
            self.start_btn = QPushButton("🚀 开始扫描")
            self.stop_btn = QPushButton("⏹️ 停止")
            self.stop_btn.setEnabled(False)
            btn_layout.addWidget(self.start_btn)
            btn_layout.addWidget(self.stop_btn)
            layout.addLayout(btn_layout)
            
            # 进度条
            self.progress_bar = QProgressBar()
            layout.addWidget(self.progress_bar)
            
            # 统计信息
            stats_layout = QHBoxLayout()
            self.req_count_label = QLabel("请求数: 0")
            self.vuln_count_label = QLabel("漏洞: 0")
            self.data_count_label = QLabel("敏感数据: 0")
            stats_layout.addWidget(self.req_count_label)
            stats_layout.addWidget(self.vuln_count_label)
            stats_layout.addWidget(self.data_count_label)
            layout.addLayout(stats_layout)
            
            # 漏洞表格
            self.vuln_table = QTableWidget()
            self.vuln_table.setColumnCount(7)
            self.vuln_table.setHorizontalHeaderLabels([
                "类型", "参数", "值", "严重程度", "风险评分", "置信度", "位置"
            ])
            self.vuln_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            self.vuln_table.itemDoubleClicked.connect(self.show_vulnerability_details)
            layout.addWidget(self.vuln_table)
            
            # 实时日志
            layout.addWidget(QLabel("实时日志:"))
            self.log_edit = QTextEdit()
            self.log_edit.setReadOnly(True)
            self.log_edit.setMaximumHeight(200)
            layout.addWidget(self.log_edit)
            
            group.setLayout(layout)
            return group

        def _connect_signals(self):
            """连接信号"""
            self.start_btn.clicked.connect(self.start_scan)
            self.stop_btn.clicked.connect(self.stop_scan)
            self.scan_started.connect(self.on_scan_started)
            self.scan_finished.connect(self.on_scan_finished)

        def start_scan(self):
            """开始扫描"""
            if self.scan_is_running:
                QMessageBox.warning(self, "警告", "扫描已在进行中！")
                return
            
            url = self.url_input.text().strip()
            if not url:
                QMessageBox.warning(self, "错误", "请输入目标URL")
                return
            
            try:
                headers = json.loads(self.headers_edit.toPlainText())
            except json.JSONDecodeError:
                QMessageBox.warning(self, "配置错误", "请求头必须是合法的JSON")
                return
            
            body = self.body_edit.toPlainText()
            data = {}
            if body:
                try:
                    data = json.loads(body)
                except json.JSONDecodeError:
                    QMessageBox.warning(self, "配置错误", "请求体必须是合法的JSON")
                    return
            
            # 清空之前的结果
            self.vuln_table.setRowCount(0)
            self.test_process_tab.clear()
            self.vuln_details_tab.clear()
            self.log_edit.clear()
            
            # 更新配置
            self.config.set("detection.https_only", self.https_only_check.isChecked(), save=False)
            self.config.set("detection.check_response", self.check_response_check.isChecked(), save=False)
            
            # 创建扫描器
            self.scanner = AsyncSensitiveDataScanner(self.config)
            
            target = {
                "url": url,
                "method": self.method_combo.currentText(),
                "headers": headers,
                "data": data
            }
            
            # 创建工作线程
            self.scan_thread = QThread()
            self.scan_worker = ScanWorker(self.scanner, target)
            self.scan_worker.moveToThread(self.scan_thread)
            self.scan_worker.log_signal.connect(self.append_log)
            self.scan_worker.progress_signal.connect(self.progress_bar.setValue)
            self.scan_worker.result_signal.connect(self.on_vulnerability_found)
            self.scan_worker.finished_signal.connect(self.on_scan_thread_finished)
            self.scan_thread.started.connect(self.scan_worker.run)
            
            self.scan_is_running = True
            self.scan_thread.start()
            self.scan_started.emit()

        def stop_scan(self):
            """停止扫描"""
            if self.scan_thread and self.scan_thread.isRunning():
                self.scan_worker.stop()
                self.scan_thread.quit()
                self.scan_thread.wait()
                self.scan_is_running = False
                self.scan_thread = None
                self.scan_worker = None
                self.scan_finished.emit([])

        def import_request(self):
            """导入请求文件"""
            file_path, _ = QFileDialog.getOpenFileName(
                self, "选择请求文件", "", "JSON Files (*.json);;HAR Files (*.har);;All Files (*)"
            )
            if file_path:
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        data = json.load(f)
                    
                    # 解析HAR或JSON格式
                    if 'log' in data:  # HAR格式
                        entries = data['log']['entries'][0]
                        request = entries['request']
                        self.url_input.setText(request['url'])
                        self.method_combo.setCurrentText(request['method'])
                        
                        headers = {}
                        for header in request['headers']:
                            headers[header['name']] = header['value']
                        self.headers_edit.setPlainText(json.dumps(headers, indent=2))
                        
                        if 'postData' in request:
                            self.body_edit.setPlainText(request['postData']['text'])
                    else:  # 自定义JSON格式
                        self.url_input.setText(data.get('url', ''))
                        self.method_combo.setCurrentText(data.get('method', 'POST'))
                        self.headers_edit.setPlainText(json.dumps(data.get('headers', {}), indent=2))
                        self.body_edit.setPlainText(json.dumps(data.get('data', {}), indent=2))
                    
                    QMessageBox.information(self, "成功", "请求导入成功！")
                except Exception as e:
                    QMessageBox.warning(self, "错误", f"文件解析失败: {e}")

        def append_log(self, message: str):
            """追加日志"""
            self.log_edit.append(f"[{datetime.now().strftime('%H:%M:%S')}] {message}")
            
            # 自动滚动到底部
            cursor = self.log_edit.textCursor()
            cursor.movePosition(QTextCursor.End)
            self.log_edit.setTextCursor(cursor)
            
            if self.scanner:
                self.req_count_label.setText(f"请求数: {self.scanner.test_process.requests_sent}")
                self.data_count_label.setText(f"敏感数据: {self.scanner.test_process.sensitive_data_found}")

        def on_vulnerability_found(self, vuln: Vulnerability):
            """发现漏洞"""
            # 去重检查
            for row in range(self.vuln_table.rowCount()):
                if (self.vuln_table.item(row, 0).text() == vuln.type and 
                    self.vuln_table.item(row, 1).text() == vuln.param):
                    return
            
            # 添加新行
            row = self.vuln_table.rowCount()
            self.vuln_table.insertRow(row)
            self.vuln_table.setItem(row, 0, QTableWidgetItem(vuln.type))
            self.vuln_table.setItem(row, 1, QTableWidgetItem(vuln.param))
            
            value_display = vuln.value[:30] + "..." if len(vuln.value) > 30 else vuln.value
            self.vuln_table.setItem(row, 2, QTableWidgetItem(value_display))
            
            # 严重程度颜色
            severity_item = QTableWidgetItem(vuln.severity)
            color = Vulnerability.RISK_LEVELS.get(vuln.severity, {}).get("color", "#000000")
            severity_item.setForeground(QColor(color))
            self.vuln_table.setItem(row, 3, severity_item)
            
            self.vuln_table.setItem(row, 4, QTableWidgetItem(str(vuln.risk_score)))
            self.vuln_table.setItem(row, 5, QTableWidgetItem(f"{vuln.confidence:.0%}"))
            self.vuln_table.setItem(row, 6, QTableWidgetItem(vuln.test_details.get('location', 'unknown')))
            
            # 存储完整漏洞对象
            self.vuln_table.item(row, 0).setData(Qt.UserRole, vuln)
            
            self.vuln_count_label.setText(f"漏洞: {row + 1}")

        def show_vulnerability_details(self, item):
            """显示漏洞详情"""
            row = item.row()
            vuln = self.vuln_table.item(row, 0).data(Qt.UserRole)
            if vuln:
                html = self._generate_vulnerability_html(vuln)
                self.vuln_details_tab.setHtml(html)
                self.tab_widget.setCurrentWidget(self.vuln_details_tab)

        def _generate_vulnerability_html(self, vuln: Vulnerability) -> str:
            """生成漏洞详情HTML"""
            risk_level = Vulnerability.RISK_LEVELS.get(vuln.severity, {})
            color = risk_level.get("color", "#000000")
            
            html = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <style>
                    body {{
                        font-family: 'Segoe UI', sans-serif;
                        background: #1e1e1e;
                        color: #d4d4d4;
                        padding: 20px;
                    }}
                    .header {{
                        border-left: 5px solid {color};
                        padding-left: 20px;
                        margin-bottom: 30px;
                    }}
                    .header h1 {{
                        color: {color};
                        margin: 0;
                        font-size: 24px;
                    }}
                    .section {{
                        background: #252526;
                        padding: 20px;
                        margin: 20px 0;
                        border-radius: 8px;
                        border: 1px solid #3e3e42;
                    }}
                    .section h3 {{
                        color: #007acc;
                        margin-top: 0;
                        border-bottom: 2px solid #007acc;
                        padding-bottom: 10px;
                    }}
                    .metric {{
                        display: inline-block;
                        margin: 10px 30px 10px 0;
                    }}
                    .metric-label {{
                        color: #888;
                        font-size: 12px;
                    }}
                    .metric-value {{
                        font-size: 28px;
                        font-weight: bold;
                        color: {color};
                    }}
                    .code {{
                        background: #1e1e1e;
                        color: #4ade80;
                        padding: 15px;
                        border-radius: 4px;
                        font-family: 'Courier New', monospace;
                        overflow-x: auto;
                        border: 1px solid #3e3e42;
                        white-space: pre-wrap;
                    }}
                    ul {{
                        padding-left: 20px;
                    }}
                    li {{
                        margin: 10px 0;
                    }}
                </style>
            </head>
            <body>
                <div class="header">
                    <h1>[{vuln.severity}] {vuln.type.replace('_', ' ').title()}</h1>
                    <p>{risk_level.get('description', '')}</p>
                    <p><strong>OWASP类别:</strong> {risk_level.get('owasp_category', 'N/A')}</p>
                </div>
                
                <div class="section">
                    <h3>📊 风险评估</h3>
                    <div class="metric">
                        <div class="metric-label">风险评分</div>
                        <div class="metric-value">{vuln.risk_score}/10</div>
                    </div>
                    <div class="metric">
                        <div class="metric-label">置信度</div>
                        <div class="metric-value">{vuln.confidence:.0%}</div>
                    </div>
                    <div class="metric">
                        <div class="metric-label">严重程度</div>
                        <div class="metric-value">{vuln.severity}</div>
                    </div>
                </div>
                
                <div class="section">
                    <h3>🔍 漏洞详情</h3>
                    <p><strong>参数名:</strong> <code>{vuln.param}</code></p>
                    <p><strong>敏感值:</strong> <code>{vuln.value[:50]}{'...' if len(vuln.value) > 50 else ''}</code></p>
                    <p><strong>发现位置:</strong> {vuln.test_details.get('location', 'unknown')}</p>
                    <p><strong>传输协议:</strong> {vuln.test_details.get('protocol', 'unknown')}</p>
                    <p><strong>证据:</strong> {vuln.evidence}</p>
                    <p><strong>发现时间:</strong> {vuln.timestamp.strftime('%Y-%m-%d %H:%M:%S')}</p>
                </div>
                
                <div class="section">
                    <h3>⚠️ 漏洞危害</h3>
                    <p><strong>影响描述:</strong></p>
                    <p>{vuln.impact.get('impact', '未知影响')}</p>
                    
                    <p><strong>潜在后果:</strong></p>
                    <ul>
                        {''.join(f'<li>{c}</li>' for c in vuln.impact.get('consequences', []))}
                    </ul>
                </div>
                
                <div class="section">
                    <h3>🛠️ 修复建议</h3>
                    <p><strong>立即修复 (0-24小时):</strong></p>
                    <ul>
                        {''.join(f'<li>{r}</li>' for r in vuln.remediation.get('immediate', []))}
                    </ul>
                    
                    <p><strong>短期修复 (1-7天):</strong></p>
                    <ul>
                        {''.join(f'<li>{r}</li>' for r in vuln.remediation.get('short_term', []))}
                    </ul>
                    
                    <p><strong>长期改进 (1-4周):</strong></p>
                    <ul>
                        {''.join(f'<li>{r}</li>' for r in vuln.remediation.get('long_term', []))}
                    </ul>
                    
                    <p><strong>代码示例:</strong></p>
                    <div class="code">{vuln.remediation.get('code_example', '请参考安全编码指南')}</div>
                </div>
            </body>
            </html>
            """
            return html

        def on_scan_started(self):
            """扫描开始"""
            self.start_btn.setEnabled(False)
            self.stop_btn.setEnabled(True)
            self.progress_bar.setValue(0)
            self.statusBar().showMessage("扫描进行中...")

        def on_scan_finished(self, vulns: List[Vulnerability]):
            """扫描完成"""
            self.start_btn.setEnabled(True)
            self.stop_btn.setEnabled(False)
            self.progress_bar.setValue(100)
            self.statusBar().showMessage(f"扫描完成，发现 {len(vulns)} 个漏洞")
            
            # 显示测试过程
            if self.scanner and self.scanner.test_process:
                html = self._generate_test_process_html()
                self.test_process_tab.setHtml(html)
            
            # 保存报告
            if vulns:
                report_file = self.save_report(vulns)
                QMessageBox.information(self, "完成", f"扫描完成！\n\n发现 {len(vulns)} 个漏洞\n报告已保存至:\n{report_file}")
            else:
                QMessageBox.information(self, "完成", "扫描完成！\n\n✅ 未发现敏感信息明文传输漏洞")

        def _generate_test_process_html(self) -> str:
            """生成测试过程HTML"""
            test_process = self.scanner.test_process
            
            duration = 0
            if test_process.start_time and test_process.end_time:
                duration = (test_process.end_time - test_process.start_time).total_seconds()
            
            html = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <style>
                    body {{
                        font-family: 'Segoe UI', sans-serif;
                        background: #1e1e1e;
                        color: #d4d4d4;
                        padding: 20px;
                    }}
                    .summary {{
                        background: #252526;
                        padding: 20px;
                        border-radius: 8px;
                        margin-bottom: 20px;
                        border: 1px solid #3e3e42;
                    }}
                    .timeline {{
                        position: relative;
                        padding: 20px 0;
                    }}
                    .timeline-item {{
                        position: relative;
                        padding: 15px;
                        margin: 10px 0;
                        background: #252526;
                        border-radius: 4px;
                        border-left: 3px solid #007acc;
                    }}
                    .level-INFO {{ border-left-color: #17a2b8; }}
                    .level-SUCCESS {{ border-left-color: #28a745; }}
                    .level-WARNING {{ border-left-color: #ffc107; }}
                    .level-ERROR {{ border-left-color: #dc3545; }}
                    .details {{
                        margin-top: 10px;
                        padding: 10px;
                        background: #1e1e1e;
                        border-radius: 4px;
                        font-size: 12px;
                    }}
                </style>
            </head>
            <body>
                <div class="summary">
                    <h2>📋 测试摘要</h2>
                    <p><strong>开始时间:</strong> {test_process.start_time.strftime('%Y-%m-%d %H:%M:%S') if test_process.start_time else 'N/A'}</p>
                    <p><strong>结束时间:</strong> {test_process.end_time.strftime('%Y-%m-%d %H:%M:%S') if test_process.end_time else 'N/A'}</p>
                    <p><strong>总耗时:</strong> {duration:.2f} 秒</p>
                    <p><strong>发送请求:</strong> {test_process.requests_sent} 个</p>
                    <p><strong>接收响应:</strong> {test_process.responses_received} 个</p>
                    <p><strong>错误数:</strong> {test_process.errors_encountered} 个</p>
                    <p><strong>敏感数据:</strong> {test_process.sensitive_data_found} 条</p>
                </div>
                <div class="timeline">
            """
            
            for step in test_process.steps:
                html += f"""
                <div class="timeline-item level-{step['level']}">
                    <div style="color: #888; font-size: 12px;">{step['timestamp']}</div>
                    <div style="font-weight: bold; color: #007acc; margin: 5px 0;">{step['title']}</div>
                    <div>{step['description']}</div>
                """
                
                if step['details']:
                    html += "<div class='details'>"
                    for key, value in step['details'].items():
                        html += f"<div><strong>{key}:</strong> {value}</div>"
                    html += "</div>"
                
                html += "</div>"
            
            html += """
                </div>
            </body>
            </html>
            """
            return html

        def on_scan_thread_finished(self, vulns: List[Vulnerability]):
            """扫描线程结束"""
            self.scan_is_running = False
            if self.scan_thread:
                self.scan_thread.quit()
                self.scan_thread.wait()
                self.scan_thread = None
            if self.scan_worker:
                self.scan_worker = None
            self.on_scan_finished(vulns)

        def save_report(self, vulns: List[Vulnerability]) -> str:
            """保存HTML报告"""
            output_dir = Path(self.config.get("output.output_dir", "~/sensitivedata_reports")).expanduser()
            output_dir.mkdir(parents=True, exist_ok=True)
            
            filename = output_dir / f"sensitive_data_report_{int(time.time())}.html"
            
            critical_count = sum(1 for v in vulns if v.severity == 'CRITICAL')
            high_count = sum(1 for v in vulns if v.severity == 'HIGH')
            medium_count = sum(1 for v in vulns if v.severity == 'MEDIUM')
            max_score = max([v.risk_score for v in vulns], default=0)
            
            html = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <title>SensitiveDataHunter Pro v1.0 扫描报告</title>
                <style>
                    body {{
                        font-family: 'Segoe UI', sans-serif;
                        background: #f5f5f5;
                        margin: 0;
                        padding: 20px;
                    }}
                    .container {{
                        max-width: 1400px;
                        margin: 0 auto;
                        background: white;
                        padding: 40px;
                        border-radius: 8px;
                        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                    }}
                    h1 {{
                        color: #dc3545;
                        border-bottom: 3px solid #dc3545;
                        padding-bottom: 15px;
                    }}
                    .executive-summary {{
                        background: #fff3cd;
                        border: 1px solid #ffc107;
                        padding: 20px;
                        border-radius: 8px;
                        margin: 20px 0;
                    }}
                    .summary-stats {{
                        display: flex;
                        justify-content: space-around;
                        margin: 30px 0;
                    }}
                    .stat-card {{
                        text-align: center;
                        padding: 20px;
                        background: #f8f9fa;
                        border-radius: 8px;
                        flex: 1;
                        margin: 0 10px;
                    }}
                    .stat-value {{
                        font-size: 36px;
                        font-weight: bold;
                    }}
                    .stat-label {{
                        color: #666;
                        margin-top: 10px;
                    }}
                    .critical {{ color: #dc3545; }}
                    .high {{ color: #fd7e14; }}
                    .medium {{ color: #ffc107; }}
                    .vuln-card {{
                        background: #fff;
                        padding: 25px;
                        margin: 20px 0;
                        border-left: 5px solid #dc3545;
                        border-radius: 4px;
                        box-shadow: 0 1px 3px rgba(0,0,0,0.1);
                    }}
                    .vuln-header {{
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        margin-bottom: 15px;
                    }}
                    .vuln-title {{
                        font-size: 20px;
                        font-weight: bold;
                        color: #333;
                    }}
                    .risk-badge {{
                        padding: 5px 15px;
                        border-radius: 20px;
                        color: white;
                        font-weight: bold;
                    }}
                    .code {{
                        background: #1e1e1e;
                        color: #d4d4d4;
                        padding: 15px;
                        border-radius: 4px;
                        font-family: 'Courier New', monospace;
                        overflow-x: auto;
                        margin: 10px 0;
                        white-space: pre-wrap;
                    }}
                    .remediation {{
                        background: #e7f3ff;
                        padding: 15px;
                        border-radius: 4px;
                        margin: 15px 0;
                    }}
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>🔒 SensitiveDataHunter Pro v1.0 扫描报告</h1>
                    <p><strong>生成时间:</strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
                    
                    <div class="executive-summary">
                        <h2>📊 执行摘要</h2>
                        <p><strong>扫描目标:</strong> {vulns[0].test_details.get('url', 'N/A') if vulns else 'N/A'}</p>
                        <p><strong>发现漏洞:</strong> {len(vulns)} 个</p>
                        <p><strong>高危漏洞:</strong> {critical_count + high_count} 个</p>
                        <p><strong>最高风险评分:</strong> {max_score:.1f}/10</p>
                    </div>
                    
                    <div class="summary-stats">
                        <div class="stat-card">
                            <div class="stat-value critical">{critical_count}</div>
                            <div class="stat-label">严重漏洞</div>
                        </div>
                        <div class="stat-card">
                            <div class="stat-value high">{high_count}</div>
                            <div class="stat-label">高危漏洞</div>
                        </div>
                        <div class="stat-card">
                            <div class="stat-value medium">{medium_count}</div>
                            <div class="stat-label">中危漏洞</div>
                        </div>
                    </div>
            """
            
            # 添加漏洞详情
            for vuln in vulns:
                color = Vulnerability.RISK_LEVELS.get(vuln.severity, {}).get("color", "#000000")
                
                html += f"""
                    <div class="vuln-card">
                        <div class="vuln-header">
                            <div class="vuln-title">{vuln.type.replace('_', ' ').title()}</div>
                            <div class="risk-badge" style="background: {color};">{vuln.severity}</div>
                        </div>
                        
                        <p><strong>风险评分:</strong> <span style="color: {color}; font-size: 24px;">{vuln.risk_score}/10</span></p>
                        <p><strong>参数:</strong> <code>{vuln.param}</code></p>
                        <p><strong>敏感值:</strong> <code>{vuln.value[:50]}{'...' if len(vuln.value) > 50 else ''}</code></p>
                        <p><strong>证据:</strong> {vuln.evidence}</p>
                        
                        <div class="remediation">
                            <h3>🛠️ 修复建议</h3>
                            <p><strong>立即修复:</strong></p>
                            <ul>
                                {''.join(f'<li>{r}</li>' for r in vuln.remediation.get('immediate', []))}
                            </ul>
                            <p><strong>代码示例:</strong></p>
                            <div class="code">{vuln.remediation.get('code_example', '请参考安全编码指南')}</div>
                        </div>
                    </div>
                """
            
            html += """
                </div>
            </body>
            </html>
            """
            
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(html)
                return str(filename)
            except Exception as e:
                print(f"[!] 保存报告失败: {e}")
                return f"保存失败: {e}"

    class ScanWorker(QObject):
        """后台工作线程"""
        log_signal = pyqtSignal(str)
        progress_signal = pyqtSignal(int)
        result_signal = pyqtSignal(Vulnerability)
        finished_signal = pyqtSignal(list)

        def __init__(self, scanner: AsyncSensitiveDataScanner, target: Dict[str, Any]):
            super().__init__()
            self.scanner = scanner
            self.target = target
            self._stop_flag = False

        def stop(self):
            """停止扫描"""
            self._stop_flag = True

        def run(self):
            """执行扫描"""
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            
            def progress_callback(msg: str):
                if not self._stop_flag:
                    self.log_signal.emit(msg)
            
            try:
                if not self._stop_flag:
                    vulns = loop.run_until_complete(
                        self.scanner.scan(self.target, progress_callback)
                    )
                    
                    if not self._stop_flag:
                        # 发送每个漏洞
                        for vuln in vulns:
                            self.result_signal.emit(vuln)
                        
                        self.finished_signal.emit(vulns)
                    else:
                        self.finished_signal.emit([])
                else:
                    self.finished_signal.emit([])
            except Exception as e:
                self.log_signal.emit(f"扫描异常: {str(e)}")
                self.finished_signal.emit([])
            finally:
                loop.close()

# ==================== 8. CLI界面 ====================
class CLIApp:
    """命令行界面"""
    
    def __init__(self, config: ConfigManager):
        self.config = config
        self.console = Console() if DEPENDENCIES['rich'] else None
        self.scanner = AsyncSensitiveDataScanner(config)

    def print_banner(self):
        """打印Banner"""
        if self.console:
            banner = r"""
[bold red]╔═══════════════════════════════════════════════════════════╗
║   ____                 _ __  _           ____        __   ║
║  / __/__ ___  ___ __ _/ /_(_)  _____   / __ \___   / /__ ║
║ _\ \/ -_) _ \(_-</ // / __/ / |/ / -_) / /_/ / _ \ / / -_)║
║/___/\__/_//_/___/\_,_/\__/_/|___/\__/ /_____/\___//_/\__/ ║
║    ____        __           __  __            __           ║
║   / __ \____ _/ /_____ _   / / / /_  ______  / /____  ____ ║
║  / / / / __ `/ __/ __ `/  / /_/ / / / / __ \/ __/ _ \/ ___/║
║ / /_/ / /_/ / /_/ /_/ /  / __  / /_/ / / / / /_/  __/ /    ║
║/_____/\__,_/\__/\__,_/  /_/ /_/\__,_/_/ /_/\__/\___/_/     ║
║                                                             ║
║         [bold yellow]Kali Linux Edition :: v1.0 Pro[/bold yellow]                ║
╚═══════════════════════════════════════════════════════════╝[/bold red]
            """
            self.console.print(Panel(banner, style="bold white"))
        else:
            print("""
╔═══════════════════════════════════════════════════════════╗
║      SensitiveDataHunter Pro v1.0 - Kali Linux Edition   ║
╚═══════════════════════════════════════════════════════════╝
            """)

    def run_interactive(self):
        """交互模式"""
        self.print_banner()
        
        if self.config.get("security.require_auth", False):
            print("\n⚠️  法律警告")
            print("本工具仅用于授权的安全测试")
            confirm = input("\n输入 'YES' 确认授权: ")
            
            if confirm.strip().upper() != "YES":
                print("未授权，退出。")
                return
        
        url = input("\n目标 URL: ").strip()
        if not url:
            print("[-] URL不能为空")
            return
        
        method = input("HTTP 方法 [POST]: ").strip().upper() or "POST"
        
        headers = {}
        if input("是否添加请求头? (y/n) [n]: ").lower() == 'y':
            print("输入JSON格式请求头，按Ctrl+D结束:")
            header_lines = []
            try:
                while True:
                    line = input()
                    header_lines.append(line)
            except EOFError:
                pass
            try:
                headers = json.loads('\n'.join(header_lines))
            except json.JSONDecodeError:
                print("[-] 无效的JSON格式")
                return
        
        data = {}
        if method in ["POST", "PUT", "PATCH"]:
            print("输入请求体JSON，按Ctrl+D结束:")
            body_lines = []
            try:
                while True:
                    line = input()
                    body_lines.append(line)
            except EOFError:
                pass
            try:
                data = json.loads('\n'.join(body_lines))
            except json.JSONDecodeError:
                print("[-] 无效的JSON格式")
                return
        
        target = {
            "url": url,
            "method": method,
            "headers": headers,
            "data": data
        }
        
        print("\n[+] 开始扫描...")
        
        if DEPENDENCIES['rich'] and self.console:
            with Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                BarColumn(),
                TaskProgressColumn(),
                console=self.console
            ) as progress:
                task = progress.add_task("[cyan]正在扫描...", total=100)
                
                def update_progress(msg: str):
                    progress.update(task, advance=25, description=msg)
                
                vulns = asyncio.run(self.scanner.scan(target, update_progress))
                progress.update(task, completed=100)
        else:
            vulns = asyncio.run(self.scanner.scan(target))
            print("[+] 扫描完成!")
        
        self.display_results(vulns)
        
        if vulns:
            save_choice = input("\n保存报告? (y/n) [y]: ").lower()
            if save_choice != 'n':
                output_dir = Path(self.config.get("output.output_dir", "~/sensitivedata_reports")).expanduser()
                output_dir.mkdir(parents=True, exist_ok=True)
                filename = output_dir / f"sensitive_data_report_{int(time.time())}.html"
                self.save_report(vulns, filename)
                print(f"[+] 报告已保存: {filename}")

    def display_results(self, vulns: List[Vulnerability]):
        """显示结果"""
        if not vulns:
            if self.console:
                self.console.print("[green]✅ 未发现敏感信息明文传输漏洞[/green]")
            else:
                print("✅ 未发现敏感信息明文传输漏洞")
            return
        
        if DEPENDENCIES['rich'] and self.console:
            table = Table(title="敏感信息泄露详情", show_header=True, header_style="bold magenta")
            table.add_column("类型", style="cyan")
            table.add_column("参数", style="yellow")
            table.add_column("严重程度", style="red")
            table.add_column("风险评分", justify="right")
            table.add_column("置信度", justify="right")
            table.add_column("位置", style="dim")
            
            for vuln in vulns:
                severity_color = {
                    "CRITICAL": "bold red",
                    "HIGH": "red",
                    "MEDIUM": "yellow",
                    "LOW": "green",
                    "INFO": "dim"
                }.get(vuln.severity, "white")
                
                table.add_row(
                    vuln.type.replace('_', ' ').title(),
                    vuln.param,
                    f"[{severity_color}]{vuln.severity}[/{severity_color}]",
                    f"{vuln.risk_score:.1f}/10",
                    f"{vuln.confidence:.0%}",
                    vuln.test_details.get('location', 'unknown')
                )
            
            self.console.print(table)
            self.console.print(f"\n[bold red]⚠️  发现 {len(vulns)} 个敏感信息泄露漏洞![/bold red]")
        else:
            print(f"\n⚠️  发现 {len(vulns)} 个敏感信息泄露漏洞!")
            for i, vuln in enumerate(vulns):
                print(f"  [{i+1}] [{vuln.severity}] {vuln.type.replace('_', ' ').title()}")
                print(f"      参数: {vuln.param}")
                print(f"      风险评分: {vuln.risk_score}/10")
                print(f"      位置: {vuln.test_details.get('location', 'unknown')}")

    def save_report(self, vulns: List[Vulnerability], filename: Path):
        """保存报告"""
        # 使用与GUI相同的报告生成逻辑
        critical_count = sum(1 for v in vulns if v.severity == 'CRITICAL')
        high_count = sum(1 for v in vulns if v.severity == 'HIGH')
        medium_count = sum(1 for v in vulns if v.severity == 'MEDIUM')
        max_score = max([v.risk_score for v in vulns], default=0)
        
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>SensitiveDataHunter Pro v1.0 扫描报告</title>
            <style>
                body {{ font-family: 'Segoe UI', sans-serif; background: #f5f5f5; margin: 0; padding: 20px; }}
                .container {{ max-width: 1400px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
                h1 {{ color: #dc3545; border-bottom: 3px solid #dc3545; padding-bottom: 15px; }}
                .executive-summary {{ background: #fff3cd; border: 1px solid #ffc107; padding: 20px; border-radius: 8px; margin: 20px 0; }}
                .summary-stats {{ display: flex; justify-content: space-around; margin: 30px 0; }}
                .stat-card {{ text-align: center; padding: 20px; background: #f8f9fa; border-radius: 8px; flex: 1; margin: 0 10px; }}
                .stat-value {{ font-size: 36px; font-weight: bold; }}
                .critical {{ color: #dc3545; }}
                .high {{ color: #fd7e14; }}
                .medium {{ color: #ffc107; }}
            </style>
        </head>
        <body>
            <div class="container">
                <h1>🔒 SensitiveDataHunter Pro v1.0 扫描报告</h1>
                <p><strong>生成时间:</strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
                <div class="executive-summary">
                    <h2>📊 执行摘要</h2>
                    <p><strong>发现漏洞:</strong> {len(vulns)} 个</p>
                    <p><strong>高危漏洞:</strong> {critical_count + high_count} 个</p>
                    <p><strong>最高风险评分:</strong> {max_score:.1f}/10</p>
                </div>
                <div class="summary-stats">
                    <div class="stat-card">
                        <div class="stat-value critical">{critical_count}</div>
                        <div class="stat-label">严重漏洞</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-value high">{high_count}</div>
                        <div class="stat-label">高危漏洞</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-value medium">{medium_count}</div>
                        <div class="stat-label">中危漏洞</div>
                    </div>
                </div>
            </div>
        </body>
        </html>
        """
        
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(html)
        except Exception as e:
            print(f"[!] 保存报告失败: {e}")

# ==================== 9. 主入口 ====================
def main():
    """程序主入口"""
    parser = argparse.ArgumentParser(
        description="SensitiveDataHunter Pro v1.0 - 敏感信息明文传输检测系统",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  # GUI模式 (推荐)
  python3 sensitivedata_hunter.py --gui
  
  # CLI交互模式
  python3 sensitivedata_hunter.py --cli
  
  # 快速扫描
  python3 sensitivedata_hunter.py --url https://target.com/api/login --method POST --data '{"username":"test","password":"123"}'
  
  # 加载配置文件
  python3 sensitivedata_hunter.py --config ~/.sensitivedatahunter/config.yaml --gui
        """
    )
    parser.add_argument("--gui", action="store_true", help="启动图形界面")
    parser.add_argument("--cli", action="store_true", help="启动命令行界面")
    parser.add_argument("--url", help="目标URL")
    parser.add_argument("--method", default="POST", help="HTTP方法")
    parser.add_argument("--headers", help="请求头JSON")
    parser.add_argument("--data", help="请求体JSON")
    parser.add_argument("--config", help="配置文件路径")
    parser.add_argument("--version", action="version", version="SensitiveDataHunter Pro v1.0")

    args = parser.parse_args()

    # 检查依赖
    missing_deps = [dep for dep, available in DEPENDENCIES.items() if not available]
    if missing_deps:
        print(f"\n[!] 缺少以下依赖: {', '.join(missing_deps)}")
        print("    请运行: pip3 install " + " ".join(missing_deps))

    config = ConfigManager(args.config or "~/.sensitivedatahunter/config.yaml")

    if args.gui:
        if not DEPENDENCIES['PyQt5']:
            print("[-] PyQt5 未安装，无法启动GUI模式")
            print("    安装命令: pip3 install PyQt5")
            sys.exit(1)
        
        app = QApplication(sys.argv)
        app.setStyle("Fusion")
        window = MainWindow(config)
        window.show()
        sys.exit(app.exec_())
    
    elif args.cli or (len(sys.argv) == 1):
        cli = CLIApp(config)
        cli.run_interactive()
    
    elif args.url:
        if not DEPENDENCIES['aiohttp']:
            print("[-] aiohttp 未安装，无法执行扫描")
            print("    安装命令: pip3 install aiohttp")
            sys.exit(1)
        
        cli = CLIApp(config)
        
        headers = {}
        if args.headers:
            try:
                headers = json.loads(args.headers)
            except json.JSONDecodeError:
                print("[-] 请求头JSON格式错误")
                sys.exit(1)
        
        data = {}
        if args.data:
            try:
                data = json.loads(args.data)
            except json.JSONDecodeError:
                print("[-] 请求体JSON格式错误")
                sys.exit(1)

        target = {
            "url": args.url,
            "method": args.method,
            "headers": headers,
            "data": data
        }

        print("[+] 开始扫描...")
        vulns = asyncio.run(cli.scanner.scan(target))
        cli.display_results(vulns)
        
        if vulns:
            output_dir = Path(config.get("output.output_dir", "~/sensitivedata_reports")).expanduser()
            output_dir.mkdir(parents=True, exist_ok=True)
            filename = output_dir / f"sensitive_data_report_{int(time.time())}.html"
            cli.save_report(vulns, filename)
            print(f"[+] 报告已保存: {filename}")
    else:
        parser.print_help()

if __name__ == "__main__":
    # 检查Kali Linux环境
    if os.path.exists("/etc/os-release"):
        try:
            with open("/etc/os-release") as f:
                content = f.read().lower()
                if "kali" not in content:
                    print("[!] 警告: 未在Kali Linux中运行，部分功能可能受限")
        except Exception:
            pass

    try:
        main()
    except KeyboardInterrupt:
        print("\n[!] 用户中断，退出。")
        sys.exit(0)
    except Exception as e:
        print(f"\n[!] 致命错误: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
